#include "FTInterface.h"

#include <stdio.h>

#include "XMLConfig2.h"
#include "MyAssert.h"
#include "PacketHeader.h"
#include "OSThread.h"

#define FTINTERFACE_BUFFER_SIZE 2048

#define CDN 0

using namespace std;
CFTInterface * CFTInterface::m_Inst = NULL;

CFTInterface::CFTInterface()
 : OSTask()
{
	m_strTaskType = "CFTInterface";

	m_Port = 0;
	m_ID = 1;
	m_pBuffer = NULL;

}


CFTInterface::~CFTInterface()
{
//	printf("Quiting CFTInterface\n");

	if(m_pBuffer) delete[] m_pBuffer;
//	printf("Quit CFTInterface done\n");
}

CFTInterface *CFTInterface::GetInstance()
{
	if(!m_Inst) {
		m_Inst = new CFTInterface;
		Assert(m_Inst);
	}
	return m_Inst;
}

Bool	CFTInterface::DelInstance()
{
	if(m_Inst) {
		m_Inst->DeleteTask();
		m_Inst = NULL;
	}

	return TRUE;
}

Bool CFTInterface::Initialize()
{
	m_Socket.Open();

	m_pBuffer = new char [FTINTERFACE_BUFFER_SIZE];
	if(!m_pBuffer) return FALSE;

	UInt16 counter;
//	if(!XMLConfig::GetDownloadInfo(m_Host,m_Port,counter)) return FALSE;
	SIPandPort ipport = SConfigPara::m_DownloadInfo;	
	counter = SConfigPara::m_DLCounter;
	if( ipport.m_IP.size() == 0 ||
		ipport.m_Port == 0 ||
		counter == 0 )
		return FALSE;
	m_Host = ipport.m_IP;
	m_Port = ipport.m_Port;
	//m_Socket.Connect(ntohl(inet_addr(m_Host.c_str())),m_Port);
	
	//run self
//	OSThreadPool::RegistTask(this);
	RunTask();
	return TRUE;
}

Bool CFTInterface::Run()
{
	while(TRUE) {
		//handle msg
		MsgData gdata;
		if(PopMessage(&gdata)) {
			Bool bQuit=false;
			switch(gdata.m_MsgID)
			{
				case RFS_MSG_NORNALQUIT:
					bQuit=TRUE;
					break;
			}
			
			if(bQuit) break;
		}

		//receive a complete packet and remove msg header
		m_Mutex.Lock();
		if(!m_Socket.IsConnected()) {
				//printf("Try to connect %s:%d\n",m_Host.c_str(),m_Port);
				OS_Error Ret = m_Socket.Connect(ntohl(inet_addr(m_Host.c_str())),m_Port);
				if(Ret == OS_NoErr) printf("Connected\n");
		}
		m_Mutex.Unlock();

		OS::Sleep(1000);
	}

	//printf("CFTInterface Run quit\n");
	return TRUE;
}


Bool CFTInterface::SendData(char *vStr,UInt32 vLen,Bool vGetBack)
{
		if(!m_Socket.IsConnected()) return FALSE;

#if CDN >0
		//make header
		PackCDNPacket Packet;
		Packet.SetLength(vLen);
		Packet.SetType(CDNPacketHeader::MFT);
		Packet.SetID(m_ID++);
		if(vGetBack) Packet.SetDir(CDNPacketHeader::REQUEST);
		else Packet.SetDir(CDNPacketHeader::SINGLE);
		Packet.SetCmd(0);
		Packet.SetErrCode(0);

		struct iovec vecBuf[2];
		vecBuf[0].iov_base = Packet.GetCDNPacket();
		vecBuf[0].iov_len = sizeof(CDNPacketHeader);
		vecBuf[1].iov_base = (char*)vStr;
		vecBuf[1].iov_len = vLen;
		
		//don't care return value
		UInt32 nOutLen;
		m_Mutex.Lock();
		m_Socket.WriteV(vecBuf,2, &nOutLen);
		m_Mutex.Unlock();
#else
		UInt32 nOutLen;
		m_Mutex.Lock();
		m_Socket.Send(vStr,vLen,&nOutLen);
		m_Mutex.Unlock();

#endif
		return TRUE;
}

Bool CFTInterface::RecvData(char *vStr,UInt32 vLen,UInt32 &vOutLen,UInt32 vTimeout)
{
	for(UInt32 i = 0 ;i<vTimeout; i++) {
		fd_set FDSet;
		struct timeval m_tv;
		m_tv.tv_sec=1;
		m_tv.tv_usec=0;
	
		FD_ZERO(&FDSet);
		FD_SET(m_Socket.GetSocketFD(),&FDSet);
		
		//set read fd
		int iRet=select(m_Socket.GetSocketFD()+1,&FDSet,NULL,NULL,&m_tv);
		if(iRet < 0 ) {
			//read and let Socket break
			printf("Get error from select %d\n",iRet);
			break;
		} else if(iRet == 0) {
			continue;
		}

		//read data
		{
			OSMutexLocker Locker(&m_Mutex);
			if(FD_ISSET(m_Socket.GetSocketFD(),&FDSet)&& m_pBuffer) {
				UInt32 iLen;
				OS_Error Ret = m_Socket.Read(m_pBuffer,FTINTERFACE_BUFFER_SIZE,&iLen);
				if(Ret == OS_NoErr) {
					m_pBuffer[iLen] = 0;
	#if CDN>0
					printf("Get Response data :%s\n",m_pBuffer+sizeof(CDNPacketHeader)+4);
					ParserCDNPacket Parser(m_pBuffer);
					if(Parser.GetDir() == CDNPacketHeader::RESPONSE) {
						//Get response
						vOutLen = iLen - sizeof(CDNPacketHeader);
						if(vOutLen < vLen)	{
								::memcpy(vStr,m_pBuffer+sizeof(CDNPacketHeader),vOutLen);
								return TRUE;
						}
						else {
							printf("Receive buffer[%d:%d] is too small.\n",vLen,vOutLen);
							return FALSE;
						}
					}
	#else
					printf("Get Response data :%s\n",m_pBuffer+4);
					vOutLen = iLen;
					::memcpy(vStr,m_pBuffer,vOutLen);
					return TRUE;
	#endif
				}
			}
		}
	}
	return FALSE;
}


